/**
 * 
 */
package GUI.GameLoadWindowPackage;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.swing.AbstractAction;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.JTextField;
import javax.swing.SpringLayout;
import javax.swing.SwingConstants;
import javax.swing.WindowConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import Utils.LoadInfo;
import Utils.SpringUtilities;
import Utils.Utils;
import java.util.concurrent.CountDownLatch;
import javax.swing.JDialog;


//VS4E -- DO NOT REMOVE THIS LINE!
public class GameCreationPanel extends JPanel implements ItemListener, ChangeListener {

    private static final long serialVersionUID = 1L;
    private JPanel pnlButtons;
    private JPanel pnlContent;
    private JButton btnGO;
    private JSlider sldNumOfPlayers;
    private JLabel lblNumOfPlayers;
    private JLabel lblHeader;
    private JTextField txtGameName;
    private Boolean bAutoDice;
    private JLabel lblGameName;
    private JPanel pnlNumPlayers;
    private JPanel pnlGame;
    private JPanel pnlChkBox;
    private LoadInfo[] arrPlayers = new LoadInfo[6];
    private Boolean finished = false;
    private boolean preDefienedPlayers;
    private JCheckBox chkAutoDice;
    private JFrame parent;
    private JPanel pnlMain;
    private CountDownLatch closeSignal;

    public GameCreationPanel(JFrame parent) {
	super();
	this.parent = parent;
	// Set the Predefiened Players as False
        preDefienedPlayers = false;
	// Set the Default Automatic Dice
	bAutoDice = true;
//	setLocationRelativeTo(parent);
	// Initialize the Rest of the Components and Add them to the Frame
        initComponents();
    }

    /**
     * Creates the Game Loader Window with predefined Players
     * @param arrPlayers The Current Players Array
     */
    GameCreationPanel(JFrame parent, String gameName, LoadInfo[] arrPlayers, Integer totalPlayers, Boolean isAutoDice) {
	super();
	this.parent = parent;
        // Save the Players Array
        this.arrPlayers = arrPlayers;
        // Set the Predefiened Players as True
        preDefienedPlayers = true;
	// Set the Automatic Dice
	bAutoDice = isAutoDice;

        // Create the Slider with the Correct Value
        getPlayersNumSlider();
        // Set the Total Number of Players
        sldNumOfPlayers.setValue(totalPlayers);
        // Deny Changing the Number of Players
        sldNumOfPlayers.setEnabled(false);
        // Initialize the Rest of the Components and Add them to the Frame
        initComponents();
        // Set the Game Name
        txtGameName.setText(gameName);
        // Deny Changing the Game Name
        txtGameName.setEnabled(false);

    }

    public void setPredefiendParams(String gameName, LoadInfo[] arrPlayers, Integer totalPlayers, Boolean isAutoDice){
	// Save the Players Array
        this.arrPlayers = arrPlayers;
        // Set the Predefiened Players as True
        preDefienedPlayers = true;
	// Set the Automatic Dice
	bAutoDice = isAutoDice;

        // Create the Slider with the Correct Value
        getPlayersNumSlider();
        // Set the Total Number of Players
        sldNumOfPlayers.setValue(totalPlayers);
        // Deny Changing the Number of Players
        sldNumOfPlayers.setEnabled(false);
        // Initialize the Rest of the Components and Add them to the Frame
        initComponents();
        // Set the Game Name
        txtGameName.setText(gameName);
        // Deny Changing the Game Name
        txtGameName.setEnabled(false);

    }

    /**
     * Initialize this Frame Components
     */
    private void initComponents() {
//	setTitle("Create a New Monopoly Game");
        // Set the OS Default Look and Feel
        Utils.setLookAndFeel();
	// Set the Default Close Operation
//	setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
	// Create a New Panel
	pnlMain = new JPanel();
        // Set the Preferred Size
        int width = 726;
        int height = 330;
        pnlMain.setPreferredSize(new Dimension(width, height));
        // Centering the window
        pnlMain.setBounds(Utils.posCenterScreen(width, height));
        // Add the Buttons Panel to the South
        pnlMain.add(getButtonsPanel(), BorderLayout.SOUTH);
        // Add the Content PAnel to the Center
        pnlMain.add(getContentPanel(), BorderLayout.CENTER);
//	if(btnGO != null){
//	    // Set the Default Button
//	    pnlMain.getRootPane().setDefaultButton(btnGO);
//	}
    }

    public JPanel getMainPanel(){
	return pnlMain;
    }
    
    /**
     * Show this Frame
     */
    public Boolean showLoadWindow(CountDownLatch cntDown) {
	if(closeSignal == null){
	    closeSignal = cntDown;
	}
        // Show the Load Window
	setVisible(true);
	// Indicates that we are Finished loading the Frame
	return true;
    }

    /**
     * Create the Check Box Player Panel
     * @return The Check Box Player Panel
     */
    private JPanel getCheckBoxPanel() {
        if (pnlChkBox == null) {
            pnlChkBox = new JPanel();
            pnlChkBox.setPreferredSize(new Dimension(100, 100));
            pnlChkBox.setLayout(new SpringLayout());
            // Set the Check boxes
            setCheckBoxPanel();
        }
        return pnlChkBox;
    }

    /**
     * Set the Check Box Player Panel
     * @return The Check box Player Panel
     */
    private JPanel setCheckBoxPanel() {
        // Clear the Panel Before Adding
        pnlChkBox.removeAll();
        // Loop the Number of Players
        for (int i = 0; i < sldNumOfPlayers.getValue(); i++) {
            if (arrPlayers[i] == null) {
                PlayerCheckbox chkPlayer = getJCheckBoxComponent(i, "Player " + (i + 1) + " (Computer)", false);
                PlayerTextField txtPlayerName = getJTextFieldComponent(i, "Player " + (i + 1));
                ColorButton btnPlayerColor = getColorButton(i);
                // Add a Check box
                pnlChkBox.add(chkPlayer);
                // Add a Text Field
                pnlChkBox.add(txtPlayerName);
                // Add the Color Chooser Button
                pnlChkBox.add(btnPlayerColor);
                // Create a new Player Info
                arrPlayers[i] = new LoadInfo(txtPlayerName.getText(), 1500.0, false, true, btnPlayerColor.getColor());
            } else {
                //  Create a new Check box
                JCheckBox chkPlayer;
                // Set the Check Box Text
                if (arrPlayers[i].getIsHuman()) // Set to Human Text
                {
                    chkPlayer = getJCheckBoxComponent(i, "Player " + (i + 1) + " (Human)", arrPlayers[i].getIsHuman());
                } else // Set to Computer Text
                {
                    chkPlayer = getJCheckBoxComponent(i, "Player " + (i + 1) + " (Computer)", arrPlayers[i].getIsHuman());
                }

                // Set the Player Name
                PlayerTextField txtPlayerName = getJTextFieldComponent(i, arrPlayers[i].getPlayerName());
                // Set the Player Color
                ColorButton btnPlayerColor = getColorButton(i);
                btnPlayerColor.setColor(arrPlayers[i].getPlayerColor());
                // Check if the Players were predefiened
                if (preDefienedPlayers) {
                    // Disable the Controls
                    chkPlayer.setEnabled(false);
                    txtPlayerName.setEnabled(false);
                }
                // Add the Components
                pnlChkBox.add(chkPlayer);
                pnlChkBox.add(txtPlayerName);
                pnlChkBox.add(btnPlayerColor);
            }
        }
        // Organize all the Components in a Compact Grid
        SpringUtilities.makeCompactGrid(pnlChkBox, sldNumOfPlayers.getValue(), 3, 6, 6, 6, 6);

        // Get the Current Dimensions of the Window
        Dimension dim = this.getSize();
        dim.height = 265 + SpringUtilities.getTotalHeigth();
        // Increase the Size of the Window to fit the Added Check boxes
        this.setSize(dim);

        // Return the New Check box Panel
        return pnlChkBox;
    }

    /**
     * Create a Color Chooser Button
     * @return A Color Chooser Button
     */
    @SuppressWarnings("serial")
    private ColorButton getColorButton(Integer index) {
        final ColorButton btnGetColor = new ColorButton(pnlChkBox, index);
        // Add an Action to the Button
        btnGetColor.setAction(new AbstractAction() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                // Get the Player Color
                btnGetColor.getPlayerColor();
                // Update the Player Color
                arrPlayers[btnGetColor.getIndex()].setPlayerColor(btnGetColor.getColor());
            }
        });
        return btnGetColor;

    }

    /**
     * Create a Text Field Component
     * @param text The Default Text
     * @return A text Field Component
     */
    private PlayerTextField getJTextFieldComponent(Integer index, String text) {
        final PlayerTextField txtField = new PlayerTextField(index, text);
        // Add an Action that Clears the Text On Click
        txtField.addFocusListener(new FocusListener() {

            @Override
            public void focusLost(FocusEvent arg0) {
                // Check that the Player Name is not Empty
                if (txtField.getText().isEmpty()) // If Empty Fill it Again
                {
                    txtField.setText("Player " + (txtField.getIndex() + 1));
                }
                // Save the Results to the Players Array
                arrPlayers[txtField.getIndex()].setPlayerName(txtField.getText());
            }

            @Override
            public void focusGained(FocusEvent arg0) {
                // Check if Text Field contains the Default Player Text
                if (txtField.getText().contains("Player ")) // Clear the Text
                {
                    txtField.setText("");
                }
            }
        });
        return txtField;
    }

    /**
     * Create a Check box Component
     * @param text The Default Text of the Check box
     * @return A Check box Component
     */
    private PlayerCheckbox getJCheckBoxComponent(Integer index, String text, Boolean select) {
        PlayerCheckbox chkBox = new PlayerCheckbox(index, text, select);
        // Add an Item Listener for this Check Box
        chkBox.addItemListener(this);
        chkBox.setVisible(true);
        return chkBox;
    }

    /**
     * Creates the Number of Players Panel
     * @return The Number of Players Panel
     */
    private JPanel getNumOfPlayerPanel() {
        if (pnlNumPlayers == null) {
            pnlNumPlayers = new JPanel();
            pnlNumPlayers.setLayout(new SpringLayout());
            pnlNumPlayers.add(getNumPlayersLabel());
            pnlNumPlayers.add(getPlayersNumSlider());
            SpringUtilities.makeCompactGrid(pnlNumPlayers, 1, pnlNumPlayers.getComponentCount(), 6, 6, 10, 10);
            //			pnlNumPlayers.add(getCheckBoxPanel(), BorderLayout.SOUTH);
        }
        return pnlNumPlayers;

    }

    /**
     * Create the Number Of Players Label
     * @return A Label - Number of Players
     */
    private JLabel getNumPlayersLabel() {
        if (lblNumOfPlayers == null) {
            lblNumOfPlayers = new JLabel();
            lblNumOfPlayers.setText("Number Of Players");
            lblNumOfPlayers.setLabelFor(sldNumOfPlayers);
        }
        return lblNumOfPlayers;
    }

    /**
     * Create the Number of Players Slider
     * @return The Number of Players Slider
     */
    private JSlider getPlayersNumSlider() {
        if (sldNumOfPlayers == null) {
            sldNumOfPlayers = new JSlider();
            // Set Minimum and Maximum for the Slider
            sldNumOfPlayers.setMaximum(6);
            sldNumOfPlayers.setMinimum(2);
            // Set other Properties for the Slider
            sldNumOfPlayers.setMajorTickSpacing(1);
            sldNumOfPlayers.setPaintLabels(true);
            sldNumOfPlayers.setPaintTicks(true);
            sldNumOfPlayers.setSnapToTicks(true);
            // Set the Slider Tool tip
            sldNumOfPlayers.setToolTipText("Choose the Number of Players");
            // Set the Initialize Value
            sldNumOfPlayers.setValue(2);
            // Add a Change Listener
            sldNumOfPlayers.addChangeListener(this);
        }
        return sldNumOfPlayers;
    }

    /**
     * Create the Funds Panel
     * @return The Funds Panel
     */
    private JPanel getGamePanel() {
        if (pnlGame == null) {
            pnlGame = new JPanel(new SpringLayout());
            // Add the Funds Label
            pnlGame.add(getGameNameLabel());
            // Add the Funds Text Field
            pnlGame.add(getGameNameTextObject());
	    // Add the Dice Roll Method Check box
	    pnlGame.add(getAutoDiceCheckBox(),SpringLayout.SOUTH);
            // Organize the Components
            SpringUtilities.makeCompactGrid(pnlGame, 1, pnlGame.getComponentCount(), 6, 6, 10, 10);
        }
        return pnlGame;
    }

    /**
     * Creates the Dice Roll Method Check box
     * @return The Dice Roll Method Check box
     */
    private JCheckBox getAutoDiceCheckBox() {
        if (chkAutoDice == null) {
            chkAutoDice = new JCheckBox();
            if (bAutoDice) {
                chkAutoDice.setText("Using Automatic Dice Roll");
            } else {
                chkAutoDice.setText("Using Manual Dice Roll");
            }
            chkAutoDice.addItemListener(this);
        }
        return chkAutoDice;
    }

    /**
     * Create the Funds Text Field
     * @return The Funds Text Field
     */
    private JTextField getGameNameTextObject() {
        if (txtGameName == null) {
            txtGameName = new JTextField();
            txtGameName.setText("New Monopoly Game");
        }
        return txtGameName;
    }

    /**
     * Create the Funds Label
     * @return The Funds Label
     */
    private JLabel getGameNameLabel() {
        if (lblGameName == null) {
            lblGameName = new JLabel();
            lblGameName.setText("Monopoly Game Name");
            lblGameName.setLabelFor(txtGameName);
        }
        return lblGameName;
    }

    /**
     * Creates the Header Label
     * @return The Header Label
     */
    private JLabel getHeaderLabel() {
        if (lblHeader == null) {
            lblHeader = new JLabel();
            lblHeader.setFont(new Font("Calibri", Font.BOLD | java.awt.Font.ITALIC, 24));
            lblHeader.setHorizontalAlignment(SwingConstants.CENTER);
            lblHeader.setIcon(Utils.getImageIcon("/icon.png"));
            lblHeader.setText("Welcome to the Java Monopoly Game!");
        }
        return lblHeader;
    }

    /**
     * Creates the Main Content Panel
     * @return The Content Panel
     */
    private JPanel getContentPanel() {
        if (pnlContent == null) {
            pnlContent = new JPanel();
            pnlContent.setLayout(new BoxLayout(pnlContent, BoxLayout.PAGE_AXIS));
            pnlContent.add(getHeaderLabel(), BorderLayout.NORTH); // Header Label
            pnlContent.add(getGamePanel(), BorderLayout.WEST); // Game Name Panel
            pnlContent.add(getNumOfPlayerPanel(), BorderLayout.CENTER); // Number Of Players Panel
            pnlContent.add(getCheckBoxPanel(), BorderLayout.SOUTH);

        }
        return pnlContent;
    }

    /**
     * Creates the Buttons Panel
     * @return The Buttons Panel
     */
    private JPanel getButtonsPanel() {
        if (pnlButtons == null) {
            pnlButtons = new JPanel();
            pnlButtons.setPreferredSize(new Dimension(50, 50));
            pnlButtons.add(getGOButton());
        }
        return pnlButtons;
    }

    /**
     * Create the Start the Game Button
     * @return The Button Component
     */
    private JButton getGOButton() {
        if (btnGO == null) {
            btnGO = new JButton();
            btnGO.setText("Start The Game");
	    btnGO.addActionListener(new ActionListener() {
		    public void actionPerformed(ActionEvent event) {
			    btnGOActionActionPerformed(event);
		    }
	    });
        }
        return btnGO;
    }

    public void addGoBtnAction(ActionListener listener){
	btnGO.addActionListener(listener);
    }

    	/**
	 * Closes this Frame
	 * @param event The Action that Fired
	 */
    private void btnGOActionActionPerformed(ActionEvent event) {
	// Delete all the players that are not needed
	for (int i = sldNumOfPlayers.getValue(); i < arrPlayers.length; i++) {
	    arrPlayers[i] = null;
	}

	// Mark as Finished
	finished = true;
	// Count Down the Close Signal
	closeSignal.countDown();
	// Close the Frame
//	this.dispose();
    }

    /**
     * Returns the Players Array Info
     * @return Players Array Info as Array of LoadInfo
     */
    public LoadInfo[] getPlayersArray() {
        return arrPlayers;
    }

    /**
     * Check if a String has only Numbers
     * For any error it pops a Dialog and sets back to the Default Value
     * @param source The Source Panel to show the Dialogs in
     * @param value The Value to Check
     * @param defValue The Default Value for Any error
     * @return
     */
    private Boolean checkStringNumbers(Component source, String value) {
        // Set a RegEx Pattern that Matches Non Digits
        Pattern pattern = Pattern.compile("^[\\d]+$");
        Matcher matcher = pattern.matcher(String.valueOf(value));
        // Check the Text Changed
        if (value.isEmpty()) {
            // Show Error Message
            JOptionPane.showMessageDialog(
                    source,
                    "Empty Input is not Allowed",
                    "Invalid Input",
                    JOptionPane.ERROR_MESSAGE);
            // Set back to the Default Funds number
            return false;
        } // Check if we can Find a Non Digit - if yes Error!
        else if (!matcher.find()) {
            // Show Error Message
            JOptionPane.showMessageDialog(
                    source,
                    "Only Numbers are Allowed",
                    "Invalid Input",
                    JOptionPane.ERROR_MESSAGE);
            // Set back to the Default Funds number
            return false;
        } else {
            return true;
        }


    }

    /**
     * Changes the State of the Check boxes in the Frame
     *   Checks the State of the Player Check boxes
     *   Changes the Dice Roll Method
     * @see java.awt.event.ItemListener#itemStateChanged(java.awt.event.ItemEvent)
     */
    public void itemStateChanged(ItemEvent e) {
        try {
            if (e.getSource() instanceof PlayerCheckbox) {
                // Set the Source Component
                PlayerCheckbox source = ((PlayerCheckbox) (e.getSource()));
                // Check if the Item has been selected
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    // Change the Text in the Check box From Computer to Human
                    source.setText(source.getText().replace("Computer", "Human"));
                } else // Check box was switched from Checked to Unchecked
                {
                    // Change the Text in the Check box From Human to Computer
                    source.setText(source.getText().replace("Human", "Computer"));
                }

                // Update the Player Info
                arrPlayers[source.getIndex()].setIsHuman(source.isSelected());
            } else {
                // Set the Source Component
                JCheckBox source = (JCheckBox) e.getSource();
                // Check if the Item has been Selected
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    // Change the Text in the Check box to Using Automatic Dice Roll
                    source.setText("Using Automatic Dice Roll");
                } else {
                    // Change the Text in the Check box to Using Manual Dice Roll
                    source.setText("Using Manual Dice Roll");
                }
            }
        } catch (ClassCastException c) {
            // Not the Class we Intended...
        }
    }

    /**
     * Checks the State of the Player Number Slider
     * @see javax.swing.event.ChangeListener#stateChanged(javax.swing.event.ChangeEvent)
     */
    public void stateChanged(ChangeEvent e) {
        try {
            JSlider source = (JSlider) e.getSource();
            if (!source.getValueIsAdjusting()) {
                // Remove the Initial Check box Panel
                pnlContent.remove(pnlChkBox);
                // Add the New Check box Panel with all the Buttons and the Check boxes
                pnlContent.add(setCheckBoxPanel());
            }
        } catch (ClassCastException c) {
            // Not the Class that we were looking for
        }
    }

    /**
     * Closes this Frame
     * @param event The Action that Fired
     */
    public  void checkAndClose(){
        // Delete all the players that are not needed
        for (int i = sldNumOfPlayers.getValue(); i < arrPlayers.length; i++) {
            arrPlayers[i] = null;
        }

        // Mark as Finished
        finished = true;
    }

    /**
     * Update all the Players with the new Funds
     * @param value The New Funds Text
     */
    private void updatePlayers(String value) {
        // Update all the Players
        for (int i = 0; i < sldNumOfPlayers.getValue(); i++) {
            arrPlayers[i].setInitFunds(Double.parseDouble(value));
        }
    }

    /**
     * Returns If the Game is Played with Automatic Dice Roll or Manual
     * @return The State of the Automatic Dice Roll
     */
    public Boolean getAutomaticDices() {
        return bAutoDice;
    }

    /**
     * Returns the Game Name
     * @return The Game Name as String
     */
    public String getGameName() {
        return txtGameName.getText();
    }


    /**
     * Checks if the Form is Finished
     * @return Is the Form Finished
     */
    public Boolean isDone(){
	return finished;
    }

    public final Boolean getFinished() {
	return finished;
    }

}

